﻿// Project: EnumDataSourceControl, File: EnumExtensions.cs
// Namespace: Salient.Util, Class: EnumExtensions
// Author: Sky Sanders (sky.sanders@gmail.com)

// Creation date: 10/15/2008 8:33 PM
// Last modified: 10/16/2008 7:20 AM


#region
using System;
using System.ComponentModel;
using System.Reflection;
using System.Web.Compilation;
using System.Collections.Generic;
#endregion

/// <summary>
/// Salient. util
/// </summary>
namespace Salient.Util
{

    public enum TestEnum01
    {
        [Description("Value One")]
        valueone,
        valuetwo,
        [Description("Value Three")]
        valuethree
    } // enum TestEnum01

    [Flags]
    public enum TestEnumFlags01
    {
        [Description("Value One")]
        valueone = 1,
        valuetwo = 2,
        [Description("Value Four")]
        valuefour = 4
    } // enum TestEnumFlags01


    /// <summary>
    /// 
    /// various enum utilities
    /// </summary>
    /// <remarks>to be extended in fx Salient.Web.UI.WebControls35 lib as enum extension methods</remarks>
    public static class EnumExtensions
    {
        /// <summary>
        /// Reconsititues an enum value from a string representation that may contain the optional description values. If the string contains only intrinsic name values Enum.Parse may be used instead.
        /// </summary>
        /// <param name="name">name or decscription of enum value</param>
        /// <returns></returns>
        /// <remarks>GetValue behaviour depends on the description being unique within the enum, that the description does not contain comma and that the description for a name does not collide with the name of any other member of the enum.
        /// These considerations do not apply if the enum name is supplied
        /// </remarks>
        public static Enum GetValue(Type enumType, string description)
        {

            List<string> entries = new List<string>();
            foreach (string value in description.Split(','))
                entries.Add(value.Trim());

            List<string> result = new List<string>();

            foreach (Enum value in Enum.GetValues(enumType))
            {
                if (entries.Contains(value.ToString()) || entries.Contains(GetDescription(value).Trim()))
                {
                    result.Add(value.ToString());
                } // if
            } // foreach  (value)
            string resultString = string.Join(", ", result.ToArray());
            return Enum.Parse(enumType, resultString) as Enum;

        } // GetValue(enumType, description)

        /// <summary>
        /// loosely typed overload for GetValue()
        /// </summary>
        /// <param name="enumTypeFullName"></param>
        /// <param name="description"></param>
        /// <returns></returns>
        /// <remarks>
        /// <para>does not resolve enums that are not in mscorlib - see GetEnumType ??</para>
        /// </remarks>
        public static Enum GetValue(string enumTypeFullName, string description)
        {
            return GetValue(GetEnumType(enumTypeFullName), description);
        } // GetValue(enumTypeFullName, description)

        /// <summary>
        /// Gets Description attribute or name of enum value in that order of precedence.
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        /// <remarks>this is found code. need to google it and attribute.</remarks>
        public static string GetDescription(Enum value)
        {
            // Check for Enum that is marked with FlagAttribute         
            string[] entries = value.ToString().Split(',');
            string[] description = new string[entries.Length];
            for (int i = 0; i < entries.Length; i++)
            {
                FieldInfo fieldInfo = value.GetType().GetField(entries[i].Trim());
                DescriptionAttribute[] attributes =
                    (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
                description[i] = (attributes.Length > 0) ? attributes[0].Description : entries[i].Trim();
            } // for
            return String.Join(", ", description);
        } // GetDescription(value)



        /// <summary>
        /// Parses type fullname, e.g. System.Drawing.KnownColor, and returns resolved type.
        /// </summary>
        /// <param name="enumTypeFullName"></param>
        /// <returns></returns>
        /// <remarks>room for improvement. especially r.e. types defined in website projects
        /// <para>does not resolve enums that are not in mscorlib</para>
        /// </remarks>
        public static Type GetEnumType(string enumTypeFullName)
        {
            Type type;
            type = BuildManager.GetType(enumTypeFullName, false, true);

            if (type == null)
                type = Type.GetType(enumTypeFullName);

            if (type == null)
                throw new Exception("could not create type " + enumTypeFullName);

            if (!type.IsEnum)
                throw new Exception(enumTypeFullName + " is not an enum");

            return type;
        } // GetEnumType(enumTypeFullName)

        /// <summary>
        /// Returns integrally typed object for specified enum value.
        /// sorry about your heap.
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static object GetTypedValue(Enum value)
        {
            object valueToReturn = value;
            switch (value.GetTypeCode())
            {
                case TypeCode.Byte:
                    valueToReturn = (byte)((object)value);
                    break;
                case TypeCode.Int16:
                    valueToReturn = (short)((object)value);
                    break;
                case TypeCode.Int32:
                    valueToReturn = (int)((object)value);
                    break;
                case TypeCode.Int64:
                    valueToReturn = (long)((object)value);
                    break;
            } // switch
            return valueToReturn;
        } // GetTypedValue(value)
    } // class EnumExtensions
} // namespace Salient.Util
